import RsaUtil from './rsa/index';
import type { Config } from '@/encrypt/types/index';

export default class ZmnEncrypt {
  /** 请求体加密公钥 */
  private reqPublicKey: string;

  /** 响应体解密私钥 */
  private resPrivateKey: string;

  /** 加解密验证字段 */
  private validateKeys?: string[];

  /** 加密验证字段 */
  private encryptKeys?: string[];

  /** 解密验证字段 */
  private decryptKeys?: string[];

  /** 预处理后的加密匹配规则（正则或字符串） */
  private encryptRules: (RegExp | string)[] = [];

  /** 预处理后的解密匹配规则（正则或字符串） */
  private decryptRules: (RegExp | string)[] = [];

  /**
   * 自定义加密方法
   * 
   * @param data 要加密的数据
   * @param reqPublicKey 加密公钥
   * @returns 加密后的数据
   */
  private encryptFun?: (data: any, reqPublicKey: string) => string;

  /**
   * 自定义解密方法
   * 
   * @param data 要解密的数据
   * @param resPrivateKey 解密私钥
   * @returns 解密后的数据
   */
  private decryptFun?: (data: any, resPrivateKey: string) => string;

  /**
   * 构造函数
   *
   * @param config 配置对象
   * @param isDevMode 是否开发模式，默认false
   */
  constructor(config: Config) {
    this.reqPublicKey = config?.reqPublicKey || '';
    this.resPrivateKey = config?.resPrivateKey || '';
    this.validateKeys = config?.validateKeys || [];
    this.encryptKeys = config?.encryptKeys || [];
    this.decryptKeys = config?.decryptKeys || [];
    this.encryptFun = config?.encryptFun || RsaUtil.encrypt;
    this.decryptFun = config?.decryptFun || RsaUtil.decrypt;
    
    // 预处理加密规则（合并encryptKeys和validateKeys）
    this.encryptRules = [
      ...(this.encryptKeys as string[]),
      ...(this.validateKeys as string[]),
    ].map(rule => this.parseRule(rule));

    // 预处理解密规则（合并decryptKeys和validateKeys）
    this.decryptRules = [
      ...(this.decryptKeys as string[]),
      ...(this.validateKeys as string[]),
    ].map(rule => this.parseRule(rule));
  }

  /**
 * 解析规则为正则表达式或小写字符串
 * 
 * @param {string} rule 原始规则（可能是通配符、正则字符串或普通字符串）
 * @returns {RegExp | string} 正则表达式或小写字符串
 */
  private parseRule(rule: string): RegExp | string {
    // 处理正则表达式格式（如"/mobile/i"）
    if (/^\/.*\/[gimuy]*$/.test(rule)) {
      const [pattern, flags] = rule.split(/\/(?=[^/]*$)/);
      return new RegExp(pattern.slice(1), flags);
    }

    // 处理通配符（将*转换为.*）
    if (rule.includes('*')) {
      const regexPattern = rule.replace(/\*/g, '.*').toLowerCase();
      return new RegExp(`^${regexPattern}$`, 'i'); // 整体匹配（不区分大小写）
    }

    // 普通字符串转为小写
    return rule.toLowerCase();
  }

  /**
   * 获取数据类型
   *
   * @param {data} data 要获取类型的数据
   * @returns {string} 数据类型
   */
  private getDataType(data: any): string {
    return Object.prototype.toString
      .call(data)
      .replace('[object ', '')
      .replace(']', '')
      .toLowerCase();
  }

  /**
   * 验证字段是否需要加密（支持通配符和正则）
   * 
   * @param key 字段名
   * @returns {boolean} 是否需要加密
   */
  private shouldEncryptField(key: string): boolean {
    const lowerKey = key.toLowerCase();
    return this.encryptRules.some(rule => {
      if (rule instanceof RegExp) {
        return rule.test(lowerKey);
      }
      return lowerKey === rule;
    });
  }

  /**
   * 验证字段是否需要解密
   *
   * @param {string} key 字段名
   * @returns {boolean} 是否需要解密
   */
  private shouldDecryptField(key: string): boolean {
    const lowerKey = key.toLowerCase();
    return this.decryptRules.some(rule => {
      if (rule instanceof RegExp) {
        return rule.test(lowerKey);
      }
      return lowerKey === rule;
    });
  }

  /**
   * 加密数据
   *
   * @param data 要加密的数据
   * @param publicKey 可选公钥，默认使用配置中的公钥
   * @returns {string} 加密后的数据
   */
  public encryptDataByPublicKey(data: any, publicKey?: string): string {
    const key = publicKey || this.reqPublicKey;
    return data && this.encryptFun ? this.encryptFun(data, key) : data;
  }

  /**
   * 解密数据
   *
   * @param data 要解密的数据
   * @param privateKey 可选私钥，默认使用配置中的私钥
   * @returns {string} 解密后的数据
   */
  public decryptDataByPrivateKey(data: any, privateKey?: string): string {
    const key = privateKey || this.resPrivateKey;
    return data && this.decryptFun ? this.decryptFun(data, key) : data;
  }

  /**
   * 递归处理数据
   *
   * @param {any} data 要处理的数据
   * @returns {any} 处理后的数据
   */
  public recursionData(
    data: any,
    targetFun: (data: any, key: string) => any
  ): any {
    const dataType = this.getDataType(data);
    if (dataType === 'object') {
      for (const key in data) {
        if (data.hasOwnProperty(key)) {
          const dType = this.getDataType(data[key]);
          if (dType === 'object') {
            data[key] = this.recursionData(data[key], targetFun);
          } else if (dType === 'array') {
            data[key] = data[key].map((item: any) =>
              this.recursionData(item, targetFun)
            );
          } else {
            data[key] = targetFun(data[key], key);
          }
        }
      }
    } else if (dataType === 'array') {
      return data.map((item: any) => this.recursionData(item, targetFun));
    }
    return data;
  }

  /**
   * 递归处理数据加密
   *
   * @param {any} data 要处理的数据
   * @returns {any} 处理后的数据
   */
  public getEncryptData(data: any): any {
    return this.recursionData(data, (item: any, key: string) => {
      if (this.shouldEncryptField(key)) {
        return this.encryptDataByPublicKey(item, this.reqPublicKey);
      }
      return item;
    });
  }

  /**
   * 递归处理数据解密
   *
   * @param {any} data 要处理的数据
   * @returns {any} 处理后的数据
   */
  public getDecryptData(data: any): any {
    return this.recursionData(data, (item: any, key: string) => {
      if (this.shouldDecryptField(key)) {
        return this.decryptDataByPrivateKey(item, this.resPrivateKey);
      }
      return item;
    });
  }
}
